package com.ai.service.made.impl;

import com.ai.check.CameraCheck;
import com.ai.common.CommonResponse;

import com.ai.common.exception.ServiceException;
import com.ai.entity.BasePage;
import com.ai.entity.alarm.RecordAlarmVO;
import com.ai.entity.made.RegionBase;
import com.ai.entity.made.RegionManage;
import com.ai.entity.made.camera.*;
import com.ai.entity.made.page.CameraPage;
import com.ai.entity.server.ServerPO;
import com.ai.mapper.made.CameraMapper;

import com.ai.model.excelParam.CameraExcelParam;
import com.ai.model.vo.ManageRegionS;
import com.ai.service.made.*;
import com.ai.util.GetCameraPreviewURLUtil;
import com.ai.util.SecurityUtils;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Mr.Chen
 * @since 2020-06-17
 */
@Service
@Slf4j
public class CameraServiceImpl extends ServiceImpl<CameraMapper, CameraPO> implements CameraService {

    @Resource
    IRegionBaseService iRegionBaseService;

    @Resource
    CameraService cameraService;
    @Resource
    CameraFunctionsService cameraFunctionsService;

    @Resource
    IRegionManageService iRegionManageService;


    @Resource
    ServerService service;


    @Value("${exportImportPath.camera}")
    private String realPath;


    /**
     * 通过ID查询
     *
     * @param cameraBO
     * @return
     */
    @Override
    public CommonResponse oneById(CameraBO cameraBO) {
        CameraPO cameraPO = getById(cameraBO.getId());
        CameraVO cameraVO = CameraVO.convertPOToVO(cameraPO);
        return CommonResponse.ok(cameraVO);
    }

    /**
     * 摄像头状态无法修改
     * 修改信息 state 无法修改，maxNum 无法修改
     * 非空校验
     * currentId，id
     * <p>
     * 修改前准备，下面的非空判断前提是 state 必须>0 ,id  不等于当前被修改 id
     * 如果 nickname 不为空，判断是否重复，重复则返回：nickname 已存在
     * 如果 code 不为空，判断是否重复，重复则返回：code 已存在
     * 如果 ip 不为空，判断是否重复，重复则返回：ip 已存在
     *
     * @param cameraBO
     * @return
     */
    @Override
    public CommonResponse modifyInfo(CameraBO cameraBO) {
        CameraCheck cameraCheck = new CameraCheck();
        if (cameraCheck.isCheckID(cameraBO)) {
            return cameraCheck.resultData;
        }
        CameraPO cameraPO = null;

        String code = cameraBO.getCode();
//        检查摄像头代码是否已经存在
        if (!StringUtils.isEmpty(code)) {
            List<CameraPO> list = list(new QueryWrapper<CameraPO>().eq("code", code).ne("id", cameraBO.getId()).gt("state", 0));
            if (list != null && list.size() > 0) {
                return CommonResponse.error("摄像头代码已存在");
            }
        }

//        检查摄像头名称是否已经存在
        if (!StringUtils.isEmpty(cameraBO.getNickname())) {
            List<CameraPO> list = list(new QueryWrapper<CameraPO>().eq("nickname", cameraBO.getNickname()).ne("id", cameraBO.getId()).gt("state", 0));
            if (list != null && list.size() > 0) {
                return CommonResponse.error("摄像头名已存在");
            }
        }

        // : 2024-01-15 暂时注释url的获取
//        String previewURL = GetCameraPreviewURLUtil.getCameraRtspUrl(code);
        cameraBO.setUrl(cameraBO.getUrl());

        cameraPO = CameraBO.convertBOToPO(cameraBO);
        cameraPO.setState(null);
        cameraPO.setMaxNum(null);
        // : 2023-06-07 通知算法
//        cameraFunctionsService.sendFullFunctions();

        if (updateById(cameraPO)) {
            return CommonResponse.ok("修改成功");
        }
        return CommonResponse.error("修改失败");
    }

    /**
     * 添加
     *
     * @param cameraBO
     * @return
     */
    @Override
    @Transactional
    public CommonResponse insert(CameraBO cameraBO) {
//        CameraCheck cameraCheck = new CameraCheck();
//        if (cameraCheck.isAdd(cameraBO)) {
//            return cameraCheck.resultData;
//        }
        String cameraBOCode = cameraBO.getCode();
        CameraPO cameraPO = null;
        if (!StringUtils.isEmpty(cameraBO.getCode())) {
            cameraPO = getOne(new QueryWrapper<CameraPO>().eq("code", cameraBOCode).gt("state", 0));
            if (cameraPO != null) {
                return CommonResponse.error("摄像头代码已存在");
            }
        }
        if (!StringUtils.isEmpty(cameraBO.getNickname())) {
            cameraPO = getOne(new QueryWrapper<CameraPO>().eq("nickname", cameraBO.getNickname()).gt("state", 0));
            if (cameraPO != null) {
                return CommonResponse.error("摄像头名已存在");
            }
        }
        if (StringUtils.isEmpty(cameraBO.getServerId()) || cameraBO.getServerId() == 0) {
            return CommonResponse.error("请选择服务器");
        }

        cameraPO = CameraBO.convertBOToPO(cameraBO);
        cameraPO.setState(2);
        cameraPO.setMaxNum(200);

        // TODO: 2024-01-15 暂时注释url的获取 
        //根据摄像头index从平台取流地址
//        String previewURL = "";
//        try {
//            previewURL = GetCameraPreviewURLUtil.getCameraRtspUrl(cameraBOCode);
//        } catch (Exception e) {
//            log.info("===========================  获取rtsp取流地址异常： ===========================");
//            log.error(e.getMessage(), e);
//
//            return CommonResponse.error("摄像头编码填写错误");
//
//        }
//        cameraPO.setUrl(previewURL);

        save(cameraPO);

        // : 2023-08-28 将新增摄像头绑定到当前角色管理的第一个区域上
        List<String> regionManageCode = SecurityUtils.getRegionManageCode(iRegionBaseService);
        if (!CollectionUtils.isEmpty(regionManageCode)) {
            String regionCode = regionManageCode.get(0);
            RegionBase regionBase = iRegionBaseService.getRegionBaseByCode(regionCode);
            RegionManage regionManage = new RegionManage();
            regionManage.setCameraId(cameraPO.getId().toString());
            regionManage.setRegionId(regionBase.getId().toString());
            regionManage.setCreateTime(LocalDateTime.now());
            regionManage.setUpdateTime(LocalDateTime.now());
            regionManage.setUpdateUser(SecurityUtils.getLoginUserName());
            regionManage.setCreateUser(SecurityUtils.getLoginUserName());

            iRegionManageService.save(regionManage);

        }

        // : 2023-06-07  算法接口 ，后续补上
//        cameraFunctionsService.sendFullFunctions();
//        baseSave(cameraBO.getCurrentId(), cameraPO);
        return CommonResponse.ok("添加成功");
    }


    /**
     * 删除
     * @param cameraBO
     * @return
     */
    @Override
    @Transactional
    public CommonResponse delete(CameraBO cameraBO) {
        CameraCheck cameraCheck = new CameraCheck();
        if (cameraCheck.isCheckID(cameraBO)) {
            return cameraCheck.resultData;
        }

        CameraPO cameraPO = getById(cameraBO.getId());

        removeById(cameraBO.getId());

        //删除摄像头与区域的关联关系
        iRegionManageService.remove(new QueryWrapper<RegionManage>().eq("camera_id", cameraBO.getId()));

        // : 2023-06-07  算法接口 ，后续补上
//        cameraFunctionsService.sendFullFunctions();

        return CommonResponse.ok("删除成功");
    }

    /**
     * 查询开启摄像头列表
     *
     * @param cameraBO
     * @return
     */
    @Override
    public CommonResponse   selectByOpen(CameraBO cameraBO) {
        List<CameraVO> cameraVOList = new ArrayList<>();

        cameraBO.setState(1);

        //获取当前用户所管理的所有摄像头
        HashMap<String, String> cameraRegionMap = SecurityUtils.getRegionManageCamerasCode(iRegionBaseService, iRegionManageService);

        if (CollectionUtils.isEmpty(cameraRegionMap)) {
            //当前区域没有管理任何摄像头
            return CommonResponse.ok(cameraVOList);
        }

        //获取所有摄像头code
        ArrayList<String> cameraCodes = new ArrayList<>(cameraRegionMap.keySet());
        List<CameraPO> cameraPOList = list(new QueryWrapper<CameraPO>().in("code", cameraCodes).like((!StringUtils.isEmpty(cameraBO.getNickname())), "nickname", cameraBO.getNickname()).like((!StringUtils.isEmpty(cameraBO.getCode())), "code", cameraBO.getCode()).eq("state", 1));

//        List<CameraPO> cameraPOList = list(new QueryWrapper<CameraPO>()
//                .like((!StringUtils.isEmpty(cameraBO.getNickname())), "nickname", cameraBO.getNickname())
//                .like((!StringUtils.isEmpty(cameraBO.getCode())), "code", cameraBO.getCode())
//                .eq("state", 1));
        cameraPOList.forEach(cameraPO -> {
            CameraVO cameraVO = new CameraVO();
            BeanUtils.copyProperties(cameraPO, cameraVO);
            ServerPO serverPO = service.getById(cameraVO.getServerId());
            cameraVO.setBindServerAdd(serverPO.getIp());

            cameraVOList.add(cameraVO);
        });
        return CommonResponse.ok(cameraVOList);
    }

    /**
     * 分页查询，列表查询除密码以外的所有用户信息
     *
     * @param page
     * @return
     */
    @Override
    public CommonResponse selectByPage(CameraPage page) {

        IPage<CameraVO> voIPage = new BasePage<>();
        //获取当前区域管理的摄像头
        HashMap<String, String> cameraRegionMap = SecurityUtils.getRegionManageCamerasCode(iRegionBaseService, iRegionManageService);

        if (CollectionUtils.isEmpty(cameraRegionMap)) {
            //当前区域没有管理任何摄像头
            return CommonResponse.ok(voIPage);
        }

        List<String> cameraCodes = SecurityUtils.getRegionManageCamerasCode(iRegionBaseService, iRegionManageService, cameraService,page.getRegionCodes());
        page.setCameraCodes(cameraCodes);
        QueryWrapper<CameraPO> queryWrapper = new QueryWrapper<>();
        queryWrapper = page.getQuery(queryWrapper);
        voIPage = baseMapper.cameraList(page, queryWrapper);
        return CommonResponse.ok(voIPage);
    }

    /**
     * 批量删除
     *
     * @param cameraIdBO
     * @return
     */
    @Override
    public CommonResponse bulkDelete(CameraIdBO cameraIdBO) {
        CameraCheck cameraCheck = new CameraCheck();
        if (cameraCheck.isCurrentID(cameraIdBO.getCurrentId())) {
            return cameraCheck.resultData;
        }

        List<Integer> ids = new ArrayList<>();
        if (cameraIdBO.getIds() != null && cameraIdBO.getIds().size() > 0) {
            ids = byIds(cameraIdBO.getIds());
        }
        if (ids.size() <= 0 && cameraIdBO.getCodes() != null && cameraIdBO.getCodes().size() > 0) {
            ids = byCodes(cameraIdBO.getCodes());
        }
        if (ids.size() <= 0) {
            return CommonResponse.error("请选择有效设备");
        }

        bulkDelete(ids);
        return CommonResponse.ok("移除摄像头成功");
    }

    /**
     * 查询人员流动摄像头列表
     *
     * @return
     */
    @Override
    public CommonResponse listByPersonFlow(CameraPage page) {
        IPage<CameraPO> iPage = baseMapper.listByPersonFlow(page, new QueryWrapper<CameraPO>().eq("functions.type", 2020).eq("camera.state", 1).eq("camera_function.state", 1));
        IPage<CameraVO> voIPage = iPage.convert(CameraVO::convertPOToVO);
        return CommonResponse.ok(voIPage);
    }

    @Transactional
    public void bulkDelete(List<Integer> ids) {
        try {
            ids.forEach(id -> {
                CameraPO cameraPO = new CameraPO();
                cameraPO.setState(-1);
                update(cameraPO, new QueryWrapper<CameraPO>().eq("id", id));
            });
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("数据库异常");
        }
    }

    @Override
    public List<Integer> openCameraList() {
        List<Integer> ids = baseMapper.openCameraIdList();
        if (ids.size() <= 0) {
            return null;
        }
        return ids;
    }

    @Override
    public List<Integer> pageCameraIdList(int start, int size) {
        List<Integer> ids = baseMapper.pageCameraIdList(start, size);
        if (ids.size() <= 0) {
            return null;
        }
        return ids;
    }

    private List<Integer> byIds(List<Integer> cameraIds) {
        List<Integer> ids = new ArrayList<>();
        cameraIds.forEach(id -> {
            if (getById(id) != null) {
                ids.add(id);
            }
        });
        return ids;
    }

    private List<Integer> byCodes(List<String> codes) {
        List<Integer> ids = new ArrayList<>();
        codes.forEach(code -> {
            CameraPO cameraPO = getOne(new QueryWrapper<CameraPO>().eq("code", code));
            if (cameraPO != null) {
                ids.add(cameraPO.getId());
            }
        });
        return ids;
    }

    @Override
    public CameraPO getByCode(String code) {
        return getOne(new QueryWrapper<CameraPO>().eq("code", code));
    }

    @Override
    public CommonResponse selectByFunctionType(final int type) {
        List<CameraPO> cameraPOIPage = baseMapper.selectByFunctionType(type);
        return CommonResponse.ok(cameraPOIPage);
    }

    /**
     * @param cameraIdBO
     * @return
     */
    @Override
    public CameraPO getCameraOn(CameraIdBO cameraIdBO) {
        CameraPO cameraPO = null;


        Integer id = cameraIdBO.getId();
        if (id != null && id != 0) {
            cameraPO = getById(id);
        }
        String code = cameraIdBO.getCode();

//        如果摄像头id为0，且摄像头的代号不为空，就使用代号去查找摄像头，但是如果摄像头代号为空，又能代表什么呢
        if (id == 0 && !StringUtils.isEmpty(code)) {
            cameraPO = getOne(new QueryWrapper<CameraPO>().eq("code", code));
        }
        return cameraPO;
    }

    @Override
    public void exportExcel() {

        File folder = new File(realPath);
        if (!folder.isDirectory()) {
            folder.mkdirs();
        }
        String fileName = realPath + "Camera" + System.currentTimeMillis() + ".xlsx";
        Collection<CameraExcelParam> cameraInfo = this.getCameraInfo();
        EasyExcel.write(fileName, CameraExcelParam.class).sheet("摄像头信息").doWrite(cameraInfo);
    }

    @Override
    public CommonResponse importExcel(MultipartFile multipartFile) throws IOException {


        HashMap<String, String> importErrorCameraIndexMap = new HashMap<>();
        HashMap<String, String> importSuccessCameraIndexMap = new HashMap<>();
        // 这里 需要指定读用哪个class去读，然后读取第一个sheet 文件流会自动关闭
        // 这里每次会读取3000条数据 然后返回过来 直接调用使用数据就行
        EasyExcel.read(multipartFile.getInputStream(), CameraExcelParam.class, new PageReadListener<CameraExcelParam>(dataList -> {

            dataList.forEach(cameraExcelParam -> {
                if (org.apache.commons.lang3.StringUtils.isNotBlank(cameraExcelParam.getCameraIndex())) {

                    //将导入的数据用mybatisPlus一个个添加进数据库
                    String cameraJsonParam = JSONObject.toJSONString(cameraExcelParam);
                    log.info("=========================== 导入的摄像头信息 ：{} ===========================", cameraJsonParam);
                    String cameraExcelParamIp = cameraExcelParam.getIp();//原本的摄像头code
                    String cameraIndex = cameraExcelParam.getCameraIndex();//摄像头编码
                    //首先查看当前对应的摄像头是否存在，如果不存
                    CameraPO cameraByIp = this.getByCameraIp(cameraExcelParamIp);
//                CameraPO cameraByIndex = this.getByCode(cameraIndex);
                    String rtspUrl = "";
                    try {
                        rtspUrl = GetCameraPreviewURLUtil.getCameraRtspUrl(cameraIndex);
                    } catch (Exception e) {
                        log.info("===========================  获取rtsp取流地址异常： ===========================");
                        importErrorCameraIndexMap.put(cameraExcelParamIp, cameraIndex);
                        log.error(e.getMessage(), e);
                        return;
                    }

                    if (null != cameraByIp) {
                        //说明当前的摄像头信息存在，执行更新操作，调用第三方获取当前摄像头对应的取流地址
                        //如果cameraByIndex不为空，说明code已经由原本的手动编写code，改为摄像头的index编码
                        this.update(new UpdateWrapper<CameraPO>().eq("ip", cameraExcelParamIp).set("code", cameraIndex).set("url", rtspUrl));//新取流地址
                        importSuccessCameraIndexMap.put(cameraExcelParamIp, cameraIndex+" rtsp："+rtspUrl);
                    } else {
                        //执行新增操作
                        CameraPO cameraPO = new CameraPO();
                        BeanUtils.copyProperties(cameraExcelParam, cameraPO);
                        cameraPO.setCode(cameraExcelParam.getCameraIndex());//code值对应摄像头编码
                        cameraPO.setUrl(rtspUrl);
                        //保存新增摄像头信息
                        this.save(cameraPO);
                        importSuccessCameraIndexMap.put(cameraExcelParamIp, cameraIndex+" rtsp："+rtspUrl);
                    }
                }
            });
        })).sheet().doRead();

        HashMap<Object, Object> result = new HashMap<>();
        result.put("success", importSuccessCameraIndexMap);
        result.put("error", importErrorCameraIndexMap);
        return CommonResponse.ok("导入结束", result);
    }

    @Override
    public CameraPO getByCameraIp(String cameraExcelParamIp) {

        CameraPO one = this.getOne(new QueryWrapper<CameraPO>().eq("ip", cameraExcelParamIp));

        return one;
    }

    @Override
    public CommonResponse getManageRegion() {
        //获取当前登录用户所管理的区域
        List<String> regionManageCodes = SecurityUtils.getRegionManageCode(iRegionBaseService);
        LinkedList<ManageRegionS> regionS = new LinkedList<>();
        HashMap<String, String> map = new HashMap<>();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(regionManageCodes)){
            for (String regionManageCode : regionManageCodes) {
                RegionBase regionBaseByCode = iRegionBaseService.getRegionBaseByCode(regionManageCode);
                String regionName = regionBaseByCode.getRegionName();

                ManageRegionS manageRegionS = new ManageRegionS();
                manageRegionS.setLabel(regionName);
                manageRegionS.setValue(regionManageCode);

                regionS.add(manageRegionS);
                map.put(regionManageCode,regionName);
            }
        }

        return CommonResponse.ok(regionS);


    }

    @Override
    public CommonResponse getManageCameraList() {

        //区域信息为空，自动获取当前登录用户管理的区域
        List<String> cameraCodes = SecurityUtils.getRegionManageCamerasCode(iRegionBaseService, iRegionManageService, cameraService,new LinkedList<>());
        //根据cameraCode批量查询摄像头
        List<CameraPO> cameraPOList =  cameraService.getByCodeList(cameraCodes);
        LinkedList<HashMap<String, Object>> res = new LinkedList<>();
        if (!CollectionUtils.isEmpty(cameraPOList)){
            //封装选择框数据结构
            cameraPOList.forEach(cameraPO -> {
                HashMap<String, Object> map = new HashMap<>();
                map.put("value",cameraPO.getId());
                map.put("label",cameraPO.getNickname());
                res.add(map);
            });
        }
        return CommonResponse.ok(res);
    }

    @Override
    public List<CameraPO> getByCodeList(List<String> cameraCodes) {

        List<CameraPO> cameraPOList = new LinkedList<>();
        if (CollectionUtils.isEmpty(cameraCodes)){
            return cameraPOList;
        }
        QueryWrapper<CameraPO> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("code",cameraCodes);
        cameraPOList = this.list(queryWrapper);
        return cameraPOList;
    }

    /**
     * 获取符合条件的摄像头信息
     *
     * @return
     */
    private Collection<CameraExcelParam> getCameraInfo() {

        List<CameraPO> cameraPOList = this.list();

        LinkedList<CameraExcelParam> excelParams = new LinkedList<>();
        List<CameraExcelParam> cameraExcelParamList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(cameraPOList) && cameraPOList.size() > 0) {
            cameraExcelParamList = cameraPOList.stream().map(cameraPO -> {
                CameraExcelParam cameraExcelParam = new CameraExcelParam();
                BeanUtils.copyProperties(cameraPO, cameraExcelParam);
                return cameraExcelParam;
            }).collect(Collectors.toList());
        }

        return cameraExcelParamList;
    }
}
